package com.anlogic.sdk.dumprestorememory.utils;

import java.io.File;

import org.apache.logging.log4j.Logger;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.ui.console.MessageConsole;

import com.anlogic.sdk.dumprestorememory.DumpRestoreModel;
import com.anlogic.sdk.tools.exetool.ExeTool;
import com.anlogic.sdk.utils.EnvUtils;
import com.anlogic.sdk.utils.FileUtils;
import com.anlogic.sdk.utils.ICommandLauncher;
import com.anlogic.sdk.utils.LogUtils;
import com.anlogic.sdk.utils.ProcLauncherUtils;
import com.anlogic.sdk.utils.UtilsPlugin;
import com.anlogic.sdk.utils.options.ChipType;

public class DumpRestoreMemoryUtils {
	private static Logger logger = LogUtils.getLogger(DumpRestoreMemoryUtils.class);

	public final static String PROGRAM = EnvUtils.getIDERootPath() + "/toolchain/openocd/fpsoc/bin/openocd";
	public final static String DUMP_CMD_FORMAT = "%s  -f \"%s\" -c \"%s\" %s";

	public final static String CMD_FORMAT = "%s  -f \"%s\" -c \"%s\" -c \"%s\" -c \"%s\" -c \"%s\" %s";

	private static final String DUMP_DATA = "dump_data";

	private static final String RESTORE_DATA = "restore_data";

	public static final String DUMP_SCRIPT_FILE_NAME = EnvUtils.getIDERootPath() + "/tools/dump_data";

	public static final String RESTORE_SCRIPT_FILE_NAME = EnvUtils.getIDERootPath() + "/tools/restore_data";


	private static final String CFG_FILE_PRERFIX = EnvUtils.getIDERootPath()
			+ "/toolchain/openocd/fpsoc/share/openocd/scripts/target";

	// private static final String DR1M90_DUMP_CMD = "" ;

	private static final String RESTORE_CMD = "load_image  %s %s bin %s %s";
	private static final String UPMP_CMD = "dump_image  %s %s %s";

	public static String getScriptFileName(String baseName) {
		String scriptFileName = baseName;
		if (!Platform.getOS().equals("linux")) {
			scriptFileName += ".bat";
		}
		return scriptFileName;
	}

	public static void writeScriptDump(DumpRestoreModel model) {
		logger.info("Write Dump script..");
		
			String cfgFile = getCfgFile(model.getChip());
			String serverCmd = getCmd(cfgFile, model.getBinFile(), model.getStartAddr(), model.getSize(),
					"");
			writeScript(getScriptFileName(DUMP_SCRIPT_FILE_NAME), serverCmd);
		
		logger.info("Write Dump script done");

	}

	public static void writeScriptRestore(DumpRestoreModel model) {
		logger.info("Write Restore script..");
		String cfgFile = getCfgFile(model.getChip());
		String serverCmd = getCmdRestore(cfgFile, model.getBinFile(), model.getStartAddr(), model.getSize(), "");
		writeScript(getScriptFileName(RESTORE_SCRIPT_FILE_NAME), serverCmd);
		logger.info("Write Restore script done");

	}

	public static void writeScript(String filePath, String cmd) {
		if (Platform.getOS().equals("linux")) {
			cmd = "#!/bin/bash\n\n" + cmd;
		}
		FileUtils.write(new File(filePath), cmd);
	}

	private static String getCmd(String cfgFile, String binFile, String startAddr, String size, String backcmd) {
		String dumpImage = String.format(UPMP_CMD, binFile, startAddr, size);
		return String.format(CMD_FORMAT, PROGRAM, cfgFile, "init", "halt", dumpImage, "shutdown", backcmd);
	}

	public static String getCmdRestore(String cfgFile, String binFile, String startAddr, String size, String backcmd) {
		String loadImage = String.format(RESTORE_CMD, binFile, startAddr, startAddr, size);
		return String.format(CMD_FORMAT, PROGRAM, cfgFile, "init", "halt", loadImage, "shutdown", backcmd);
	}

	

	public static String getCfgFile(String chipName) {
		String cfgFile = CFG_FILE_PRERFIX + "/anlogic/" + chipName + ".cfg";
		return cfgFile;
	}

	public static void dump(DumpRestoreModel model) {
		File pwd = new File(ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString());
		MessageConsole dumpRestoreConsole = UtilsPlugin.getDefault().getMessageConsole("Dump Tool");
		ICommandLauncher dumpLauncher = UtilsPlugin.getDefault().getLauncher(dumpRestoreConsole);
		dumpLauncher.setRedirectErrToOut(true);
		dumpLauncher.setFilterErrorMessage(true);
		logger.info("kill openocd start...");
		ProcLauncherUtils.killExecute("openocd");
		logger.info("kill openocd done");
		if (ChipType.isDr1(model.getChip()) || ChipType.isSOC66080(model.getChip())) {
			logger.info("Release the lockdown status...");
			ProcLauncherUtils.releaseLockdown();
			logger.info("Release the lockdown status done");
		}
		Job job = new Job("Dump Tool executing...") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				logger.info("Dump starting...");
				dumpLauncher.asyncLaunch(DUMP_DATA, pwd, null);
				while (!dumpLauncher.hasTerminated()) {
					try {
						Thread.sleep(100L);
					} catch (InterruptedException e) {
						logger.error("Unexpected error occurred {}", e.getMessage());
					}
					if (monitor.isCanceled()) {
						dumpLauncher.terminate();
					}
					if (dumpLauncher.hasTerminated()) {
						logger.info("Dump done.");
					}
				}
				monitor.done();
				return Status.OK_STATUS;
			}
		};
		job.schedule();
	}

	public static void restore(DumpRestoreModel model) {
		File pwd = new File(ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString());
		MessageConsole restoreConsole = UtilsPlugin.getDefault().getMessageConsole("Restore Tool");
		ICommandLauncher restoreLauncher = UtilsPlugin.getDefault().getLauncher(restoreConsole);
		restoreLauncher.setRedirectErrToOut(true);
		restoreLauncher.setFilterErrorMessage(true);
		logger.info("kill openocd start...");
		ProcLauncherUtils.killExecute("openocd");
		logger.info("kill openocd done");
		if (ChipType.isDr1(model.getChip()) || ChipType.isSOC66080(model.getChip())) {
			logger.info("Release the lockdown status...");
			ProcLauncherUtils.releaseLockdown();
			logger.info("Release the lockdown status done");
		}
		Job job = new Job("Restore Tool executing...") {
			@Override
			protected IStatus run(IProgressMonitor monitor) {
				logger.info("Restore starting...");
				restoreLauncher.asyncLaunch(RESTORE_DATA, pwd, null);
				while (!restoreLauncher.hasTerminated()) {
					try {
						Thread.sleep(100L);
					} catch (InterruptedException e) {
						logger.error("Unexpected error occurred {}", e.getMessage());
					}
					if (monitor.isCanceled()) {
						restoreLauncher.terminate();
					}
					if (restoreLauncher.hasTerminated()) {
						logger.info("Restore done.");
					}
				}
				monitor.done();
				return Status.OK_STATUS;
			}
		};
		job.schedule();

	}

}
